package util

import (
	"bufio"
	"fmt"
	"io"
	"os"
	"path"
	"strings"

	"github.com/fsnotify/fsnotify"
	log "github.com/kpango/glg"
)

func ReadAndHandleLine(fileName string, handler func(string, bool)) error {
	f, err := os.Open(fileName)
	if err != nil {
		return err
	}
	defer f.Close()
	buf := bufio.NewReader(f)
	for {
		line, err := buf.ReadString('\n')
		if err != nil {
			if err == io.EOF {
				line = strings.TrimSpace(line)
				handler(line, true)
				break
			}
			return err
		}
		line = strings.TrimSpace(line)
		handler(line, false)
	}
	return nil
}

type FileWatcher struct {
	watcher *fsnotify.Watcher
}

func NewWatcher() (*FileWatcher, error) {
	fw := &FileWatcher{
		watcher: new(fsnotify.Watcher),
	}
	watcher, err := fsnotify.NewWatcher()
	if err != nil {
		return fw, fmt.Errorf("Failed to new file watcher: %v", err)
	}
	fw.watcher = watcher
	return fw, nil
}

func (w *FileWatcher) Watch(filename string, handler func(string)) error {
	dir := path.Dir(filename)
	file := path.Base(filename)
	go func() {
		for {
			select {
			case event := <-w.watcher.Events:
				if path.Dir(event.Name) == dir && path.Base(event.Name) == file {
					log.Infof("file %s state changed, operator: %v\n", event.Name, event.Op)
					handler(filename)
				}
			case err := <-w.watcher.Errors:
				if err != nil {
					log.Infof("[Error] FileWatcher: %v\n", err)
				}
			}
		}
	}()

	if err := w.watcher.Add(dir); err != nil {
		return fmt.Errorf("FileWatcher: Failed to watch %s: %v", dir, err)
	}
	return nil
}

func (w *FileWatcher) Close() error {
	return w.watcher.Close()
}
